using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using CfgTable;

namespace IQIGame.Onigao.GamePlay
{
    public class LevelSubmitData
    {
        #region Property

        public string submitDesc { get; private set; }

        /// <summary>
        /// 提交槽数量
        /// </summary>
        public int slotCnt { get; private set; }

        /// <summary>
        /// 可提交道具列表
        /// </summary>
        public IReadOnlyList<SubmitItemData> sortedItems => _sortedItems;

        public bool ordered { get; private set; }
        #endregion

        #region Interface

        /// <summary>
        /// 组合校验
        /// </summary>
        /// <param name="judge">玩家提交的组合</param>
        /// <returns></returns>
        public bool ValidateJudge(IReadOnlyList<int> judge)
        {
            return ordered ? OrderedJudgeValidate(judge) : RandomJudgeValidate(judge);
        }

        /// <summary>
        /// 获取指定道具需要提交的数量
        /// </summary>
        /// <param name="itemCid">item配置ID</param>
        /// <returns></returns>
        public int GetAllowNeedCnt(int itemCid)
        {
            return _allowItems.GetValueOrDefault(itemCid, 0);
        }

        /// <summary>
        /// 更新提交数据
        /// </summary>
        /// <param name="submitCid">道具提交配置表ID</param>
        public void UpdateSubmitData(int submitCid)
        {
            var submitCfg = TableCenter.levelItemSubmit.Get(submitCid);
            _itemJudges.Clear();
            _allowItems = submitCfg.AllowItem;

            for (var i = 0; i < submitCfg.JudgeID.Count; i++)
            {
                var judgeCfg = TableCenter.levelItemJudge.Get(submitCfg.JudgeID[i]);
                _itemJudges.Add(judgeCfg.ItemJudge);
            }

            slotCnt = _itemJudges.First().Count;
            submitDesc = submitCfg.CustomizedDes;
            ordered = submitCfg.Type == ItemSubmitType.Ordered;

            foreach (var item in _sortedItems)
            {
                ClassPool.Put(item);
            }

            _sortedItems.Clear();

            foreach (var kvp in _allowItems)
            {
                var itemCid = kvp.Key;
                if (ItemModule.Instance.GetNum(itemCid) <= 0)
                {
                    continue;
                }

                var items = ItemModule.Instance.GetItemAllByCid(itemCid);
                var submitItemData = ClassPool.Get<SubmitItemData>();
                for (var i = 0; i < items.Count; i++)
                {
                    submitItemData.UpdateData(items[i], kvp.Value);
                }
                _sortedItems.Add(submitItemData);
            }

            _sortedItems.Sort(ItemSorter);
        }

        #endregion

        #region Method

        private static int ItemSorter(SubmitItemData a, SubmitItemData b)
        {
            if (a.sort != b.sort)
                return a.sort > b.sort ? -1 : 1;
            return a.uniqueId > b.uniqueId ? -1 : 1;
        }

        private bool OrderedJudgeValidate(IReadOnlyList<int> judge)
        {
            foreach (var itemJudge in _itemJudges)
            {
                if (OrderedJudgeEquals(judge, itemJudge))
                {
                    return true;
                }
            }

            return false;
        }

        private static bool OrderedJudgeEquals(IReadOnlyList<int> src, IReadOnlyList<int> dst)
        {
            if (src.Count != dst.Count)
            {
                return false;
            }

            for (var i = 0; i < src.Count; i++)
            {
                if (src[i] != dst[i])
                {
                    return false;
                }
            }

            return true;
        }


        /// <summary>
        /// 先排序，后比较
        /// </summary>
        /// <param name="judge">玩家提交的组合</param>
        /// <returns></returns>
        private bool RandomJudgeValidate(IReadOnlyList<int> judge)
        {
            var tempSrc = ListPool<int>.Get();
            tempSrc.AddRange(judge);
            tempSrc.Sort(ItemCidSorter);
            var tempDst = ListPool<int>.Get();
            foreach (var itemJudge in _itemJudges)
            {
                tempDst.Clear();
                tempDst.AddRange(itemJudge);
                tempDst.Sort(ItemCidSorter);
                if (!OrderedJudgeEquals(tempSrc, tempDst)) continue;
                ListPool<int>.Put(tempSrc);
                ListPool<int>.Put(tempDst);
                return true;
            }

            ListPool<int>.Put(tempSrc);
            ListPool<int>.Put(tempDst);
            return false;
        }

        private static int ItemCidSorter(int a, int b)
        {
            return a > b ? -1 : 1;
        }

        private bool RandomValidateWithBIT(IReadOnlyList<int> judge)
        {
            foreach (var itemJudge in _itemJudges)
            {
                if (RandomJudgeEquals(judge, itemJudge))
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// O(n),无GC的比较
        /// 原理：两个元素数量相同集合的元素之和以及之积相同则，这两个集合相等
        /// </summary>
        /// <param name="src">玩家提交的组合</param>
        /// <param name="dst">配置的组合</param>
        /// <returns></returns>
        private bool RandomJudgeEquals(IReadOnlyList<int> src, IReadOnlyList<int> dst)
        {
            if (src.Count != dst.Count)
            {
                return false;
            }

            if (src.Sum() != dst.Sum())
            {
                return false;
            }

            var srcProduct = new BigInteger(src.First());
            var dstProduct = new BigInteger(dst.First());
            for (var i = 1; i < src.Count; i++)
            {
                srcProduct *= src[i];
                dstProduct *= dst[i];
            }

            return srcProduct == dstProduct;
        }

        #endregion

        #region Field
        
        private readonly List<SubmitItemData> _sortedItems = new();

        private IReadOnlyDictionary<int, int> _allowItems;

        private readonly List<IReadOnlyList<int>> _itemJudges = new();

        #endregion
    }

    public class SubmitItemData : IReusableClass
    {
        //heroCid != uniqueId 则代表该道具是不可堆叠道具 默认只需要1个 不需要检查数量是否足够
        public bool canSubmit => itemCid != uniqueId || needCnt <= ItemModule.Instance.GetNum(itemCid);
        public int needCnt { get; private set; }
        public int sort { get; private set; }
        public long uniqueId { get; private set; }
        public int itemCid { get; private set; }
        public uint MaxStore => 20;

        public void UpdateData(ItemData itemData, int needCnt)
        {
            itemCid = itemData.cid;
            //普通道具用ItemCid,其他道具用server id
            uniqueId = itemData.id;
            this.needCnt = needCnt;
            sort = itemData.cfgData.Sort;
        }

        public void OnReset()
        {
            needCnt = 0;
            sort = 0;
            uniqueId = 0;
            itemCid = 0;
        }
    }
}